import * as http from "http";
import * as ws from 'ws';
import * as nodeuuid from 'node-uuid';
import { Logger,LogFactory } from './log';

export class Session{
    log:Logger = LogFactory.inst().getLogger("Session");
    ws:WebSocket;
    uuid:string;
    msgStamp:number;
    data:any;

    constructor(ws:WebSocket){
        this.ws = ws;
        this.uuid = nodeuuid.v4();
        this.msgStamp = Date.now();
    }
    expire(){
        const expireTime:number = 15000;
        return (Date.now() - this.msgStamp > expireTime);
    }
    send(data:Uint8Array|string):boolean{
        if (this.ws.readyState != 1){
            this.log.info("session uuid:", this.uuid, 
                "is not open, send failed!! state:", this.ws.readyState, "data:", data);
            return false;
        }

        try{
            this.ws.send(data);
        }catch(err){
            this.log.error("session uuid:", this.uuid, 
                "send data failed!!!, data:", data, "exception:", err);
            return false;
        }

        return true;
    }
    close(){
        try{
            this.ws.close();
        }catch(err){
            this.log.error("session uuid:", this.uuid,
                "close failed!!!, exception:", err);
        }
    }
}

export class WServer{
    log:Logger = LogFactory.inst().getLogger("WServer");
    wsmap:Map<string,Session> = new Map();
    wss:ws.Server;

    constructor(port:number){
        this.wss = new ws.Server({
            port: port, //监听接口  
        });
    }

    onconnected(ss:Session) {}
    onmessage(ss:Session, data:any) {}
    onclose(ss:Session) {}
    onerror(ss:Session, error:string) {}

    addSession(ws:WebSocket){
        let ss = new Session(ws);
        this.wsmap.set(ss.uuid, ss);
        ws.onmessage = (ev:MessageEvent) => {
            ss.msgStamp = Date.now();
            this.onmessage(ss, ev.data);
        };
        ws.onclose = (ev:CloseEvent)=>{
            this.log.info('client closed:' + ss.uuid);
            this.onclose(ss);
            this.wsmap.delete(ss.uuid);
        };
        ws.onerror = (ev:Event)=>{
            this.log.error('client error:' + ev.type + ",uuid:" + ss.uuid);
            this.onerror(ss, ev.type);
            ws.close();
        };
        this.onconnected(ss);
        return ss;
    }

    broadcast(data:any){
        for(let m of this.wsmap){
            m[1].send(data);
        }
    }

    start() {
        this.log.info("server start....", this.wss.options.port);
        this.wss.on("connection", (ws:WebSocket) => {
            this.addSession(ws);
        });

        const checkTime:number = 1000;
        setInterval(() => {
            for(let m of this.wsmap){
                let ss = m[1];
                if (ss.expire()){
                    this.log.info("session uuid:", ss.uuid, "had expired");
                    ss.close();
                }
            }
        }, checkTime);
    }
}